package cn.xuyun.cc.tcp.service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.karmafiles.ff.core.tool.dbutil.converter.Converter;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.types.ObjectId;

import cn.xuyun.cc.tcp.TcpServer;
import cn.xuyun.cc.tcp.bean.CommandInfo;
import cn.xuyun.cc.tcp.bean.CommandReq;
import cn.xuyun.cc.tcp.bean.DeviceCommand;
import cn.xuyun.cc.tcp.vo.CallBack;
import cn.xuyun.cc.tcp.vo.Entity;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.WriteResult;

public class MongoService {

	private static Log log = LogFactory.getLog(MongoService.class);


	private static Mongo m = null;

	static {
		try {
			m = new Mongo("127.0.0.1");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static boolean save(String db, String collection, Object obj) {
		DBCollection dbc = m.getDB(db).getCollection(collection);
		WriteResult wr = dbc.save(Converter.toDBObject(obj));
		log.debug(wr.getLastError().toString());
		return wr.getLastError().ok();
	}

	public static boolean delete(String db, String collection, BasicDBObject dbobj) {
		DBCollection dbc = m.getDB(db).getCollection(collection);
		WriteResult wr = dbc.remove(dbobj);
		log.debug(wr.getLastError().toString());
		return wr.getLastError().ok();
	}
	
	public static boolean update(String db, String collection, BasicDBObject query, Object obj) {
		DBCollection dbc = m.getDB(db).getCollection(collection);
		WriteResult wr = dbc.update(query, Converter.toDBObject(obj));
		return wr.getLastError().ok();
	}
	
	/**
	 * 添加命令历史
	 * @param user
	 * @param key
	 * @return
	 */
	public static boolean addCommandHistory(String user,String key)
	{
		DBCollection dbc = m.getDB("command").getCollection("command_history");
		BasicDBObject q=new BasicDBObject();
		q.put("user", user);
		
		BasicDBObject o=new BasicDBObject();
		o.put("$push", new BasicDBObject("cmdKey",key));
		WriteResult wr=dbc.update(q, o, true, true);
		
		return wr.getLastError().ok();
	}
	
	
	/**
	 * 添加新命令key到设备未完成列表
	 * @param cmdKey
	 * @param deviceId
	 * @return
	 */
	public static boolean addCmdKey2Device(String cmdKey,String deviceId)
	{
		DBCollection dbc = m.getDB("command").getCollection("device_command");
		BasicDBObject q=new BasicDBObject();
		q.put("_id", deviceId);
		BasicDBObject o=new BasicDBObject();
		o.put("$addToSet", new BasicDBObject("unfinished_cmdKey",cmdKey));
		WriteResult wr=dbc.update(q, o, true, true);
		
		return wr.getLastError().ok();
	}
	
	
	/**
	 * 获得最近的命令列表
	 * @param user
	 * @param count
	 * @return
	 */
	public static List<CommandReq> getLastCmd(String user,int count)
	{
		List<CommandReq> result =new ArrayList<CommandReq>();
		
		BasicDBObject q =new BasicDBObject();
		q.put("user", user);
		
		DBCollection dbc = m.getDB("command").getCollection("command_req");
		
		DBCursor cursor=dbc.find(q).sort(new BasicDBObject("begin_time","-1")).limit(count);
		while(cursor.hasNext())
		{
			result.add(Converter.toObject(CommandReq.class, cursor.next()));
		}
		return result;
	}
	
	/**
	 * 通过id查找cmdreq
	 * @param key
	 * @return
	 */
	public static CommandReq getCmdreqById(String key)
	{
		DBCollection dbc=m.getDB("command").getCollection("command_req");
		BasicDBObject q=new BasicDBObject();
		q.put("_id", key);
		DBObject obj=dbc.findOne(q);
		if(obj==null)return null;
		CommandReq cmdreq=Converter.toObject(CommandReq.class, obj);
		return cmdreq;
	}
	
	
	/**
	 * 获取已完成信息
	 * @param key
	 * @param deviceid
	 * @return
	 */
	public static CommandInfo getResponse(String key,String deviceid)
	{
		DBCollection dbc=m.getDB("command").getCollection("device_command");
		
		BasicDBObject q=new BasicDBObject();
		q.put("finished_cmd.key", key);
		q.put("_id", deviceid);
		
		DBObject obj=dbc.findOne(q);
		
		if(obj==null)return null;
		
		DeviceCommand dc=Converter.toObject(DeviceCommand.class, obj);
		for(CommandInfo ci:dc.getFinished_cmd())
		{
			if(ci.getKey().equals(key))
			{
				return ci;
			}
		}
		return null;
		
	}
	
	
	/**
	 * 获取马上要执行的cmd
	 * @param deviceId
	 * @return
	 */
	
	public static CommandReq getCmdreq(String deviceId)
	{
		DBCollection dbc = m.getDB("command").getCollection("device_command");
		BasicDBObject q=new BasicDBObject();
		q.put("_id", deviceId);
		
		BasicDBObject field=new BasicDBObject();
		field.put("unfinished_cmdKey", 1);
		
		DBObject obj=dbc.findOne(q, field);
		
		if(obj!=null)
		{
			DeviceCommand dc= Converter.toObject(DeviceCommand.class, obj);
			
			List<String>  cmdKey=dc.getUnfinished_cmdKey();
			
			if(cmdKey.size()>0){
				String cmdkey=cmdKey.get(0);
				dbc=m.getDB("command").getCollection("command_req");
				DBObject dbo=dbc.findOne(new BasicDBObject("_id",cmdkey));
				if(dbo!=null)
				{
					return Converter.toObject(CommandReq.class, dbo);
				}
			}
		}
		
		return null;
	}
	
	
	public static void saveResponse(String deviceId,Entity entity)
	{
		
		
		CommandReq cmdreq=getCmdreq(deviceId);
		
		if(cmdreq!=null&&cmdreq.getCmdcode()==entity.getCmd())
		{
			//match
			CommandInfo cmdinfo=new CommandInfo();
			cmdinfo.setKey(cmdreq.get_id());
			cmdinfo.setBegin_time(cmdreq.getBegin_time());
			cmdinfo.setCallback(cmdreq.getCallback());
			cmdinfo.setCmdcode(cmdreq.getCmdcode());
			cmdinfo.setEnd_time(System.currentTimeMillis());
			cmdinfo.setParam(cmdreq.getParam());
			cmdinfo.setResponse(entity.getContent());
			cmdinfo.setTimeout(cmdreq.getTimeout());
			cmdinfo.setUser(cmdreq.getUser());
			
			//step 1 add to finished queue
			DBCollection dbc = m.getDB("command").getCollection("device_command");
			BasicDBObject q=new BasicDBObject();
			q.put("_id", deviceId);
			
			BasicDBObject o=new BasicDBObject();
			o.put("$push", new BasicDBObject("finished_cmd",Converter.toDBObject(cmdinfo)));
			
			dbc.update(q, o, true, true);
			
			//step2 pop unfinished cmdkey
			
			BasicDBObject mod=new BasicDBObject();
			mod.put("$pop", new BasicDBObject("unfinished_cmdKey",-1));
			
			dbc.update(q, mod);
			
			//step3 update commandreq finished
			
			q=new BasicDBObject();
			q.put("_id", cmdreq.get_id());
			
			mod=new BasicDBObject();
			mod.put("$inc", new BasicDBObject("finished",1));
			
			dbc=m.getDB("command").getCollection("command_req");
			//DBObject query, DBObject fields, DBObject sort, boolean remove, DBObject update, boolean returnNew, boolean upsert)
			DBObject dbobj=dbc.findAndModify(q, new BasicDBObject("finished",1), null, false, mod, true, true);
			
			int finished = (Integer)dbobj.get("finished");
			
			if(finished==cmdreq.getDevice_id().size())
			{
				mod=new BasicDBObject();
				mod.put("$set", new BasicDBObject("end_time",new Date().getTime()));
				dbc.update(q, mod);
			}
			
			//add to linkQueue to push callback
			CallBack cb=new CallBack();
			cb.setDeviceId(deviceId);
			cb.setCmdCode(cmdreq.getCmdcode());
			cb.setCmdkey(cmdreq.get_id());
			cb.setCmdStr(cmdreq.getCmdstr());
			cb.setCallback(cmdreq.getCallback());
			cb.setTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			
			cb.setDeviceResponse(entity.getContent());
			
			TcpServer.linkQueue.add(cb);
			
		}else{
			log.error("device response error,id:"+deviceId);
		}
		
	}
	
	
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub

	}

}
